home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / Sound / SndPlayDoubleBuffer / _source / SND.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-15  |  9.0 KB  |  251 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Routines demonstrating how to parse 'snd ' resource files.
  5. **
  6. **    by Mark Cookson, Apple Developer Technical Support
  7. **
  8. **    File:    SND.c
  9. **
  10. **    Copyright ©1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "Apple Sample
  17. **    Code" after having made changes. If you're going to re-distribute the
  18. **    source, we require that you make it clear in the source that the code
  19. **    was descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #include "SND.h"
  23. /*
  24.     There are lots of places for reading a resource to go wrong.  This is
  25.     why I currently have the paranoid error checking.
  26.  
  27.     This routine works like the other parse header routines, except that
  28.     since it doesn't do any Resource Manager calls, it expects the file
  29.     pointer to be positioned right at the first byte of the data of the
  30.     'snd ' resource.  This way the FSRead that reads the header will work.
  31.  
  32.     The length calculation could probably use some work, but that would
  33.     require modifying the read routines.  Right now we just fudge the length
  34.     so that we will read all of a resource.
  35. */
  36. /*-----------------------------------------------------------------------*/
  37.         OSErr    ASoundGetSNDHeader        (SoundInfoPtr theSoundInfo,
  38.                                         long *dataStart,
  39.                                         long *length)
  40. /*-----------------------------------------------------------------------*/
  41. {
  42.     SoundComponentData        sndInfo;
  43.     Ptr                        theSoundHeader    = nil;
  44.     unsigned long            numFrames        = 0,
  45.                             dataOffset        = 0;
  46.     long                    headerBytes        = kMaxSNDHeaderSize;
  47.     short                    resNum            = 0;
  48.     OSErr                    theErr            = noErr;
  49.  
  50.     *dataStart = kInit;
  51.     *length = kInit;
  52.  
  53.     theSoundHeader = NewPtr (headerBytes);
  54.     theErr = MemError();
  55.     if (theSoundHeader != nil || theErr == noErr) {
  56.         /* This returns the number of the first resource of type 'snd ' */
  57.         theErr = MyGetFirstResource (theSoundInfo->refNum, 'snd ', &resNum);
  58.         if (theErr == noErr) {
  59.             theErr = MyGetResourcePosition (theSoundInfo->refNum, 'snd ', resNum, dataStart);
  60.             if (theErr == noErr) {
  61.                 theErr = FSRead (theSoundInfo->refNum, &headerBytes, theSoundHeader);
  62.                 if (theErr == noErr) {
  63.                     /* Could use SM 3.2's ParseSndHeader, but this is (supposed to be) educational */
  64.                     theErr = MyParseSndHeader (&(SndListResource*)theSoundHeader, &sndInfo, &numFrames, &dataOffset);
  65.                     if (theErr == noErr) {
  66.                         DisposePtr (theSoundHeader);                /* It's work is done */
  67.                         theErr = SetupDBHeader (theSoundInfo,
  68.                                                 sndInfo.sampleRate,
  69.                                                 sndInfo.sampleSize,
  70.                                                 sndInfo.numChannels,
  71.                                                 fixedCompression,    /* fixedCompression will work for uncompressed */
  72.                                                 sndInfo.format);    /* format is the really important field */
  73.                         theSoundInfo->needsMasking = false;            /* 'snd ' resources never need masking */
  74.                         *length = numFrames * theSoundInfo->doubleHeader.dbhPacketSize * sndInfo.numChannels;
  75.                         *dataStart += dataOffset;
  76.                     }
  77.                     else {
  78.                         DebugPrint ("\pParseSndHeader failed");
  79.                     }
  80.                 }
  81.                 else {
  82.                     DebugPrint ("\pFSRead failed");
  83.                 }
  84.             }
  85.             else {
  86.                 DebugPrint ("\pMyGetResourcePosition failed");
  87.             }
  88.         }
  89.         else {
  90.             DebugPrint ("\pMyGetFirstResource failed");
  91.         }
  92.     }
  93.     else {
  94.         DebugPrint ("\pNewPtr failed");
  95.     }
  96.  
  97.     if (theErr != noErr) {
  98.         DebugPrint ("\pError in ASoundGetSNDHeader");
  99.     }
  100.  
  101.     *length += *dataStart;    /* Otherwise we wouldn't read the last few bytes from the end of the sound. */
  102.  
  103.     return theErr;
  104. }
  105.  
  106. /*
  107.     This code parses a 'snd ' resource header.  While Sound Manager 3.2 will
  108.     do this for you, this is for education (and entertainment).  Just in case
  109.     the Sound Manager routine is better, try it first, if it's available.
  110. */
  111. /*-----------------------------------------------------------------------*/
  112.         OSErr    MyParseSndHeader        (SndListHandle theSoundHeader,
  113.                                         SoundComponentData *sndInfo,
  114.                                         unsigned long *numFrames,
  115.                                         unsigned long *dataOffset)
  116. /*-----------------------------------------------------------------------*/
  117. {
  118.     NumVersion                SndManagerVer;
  119.     headerTemplate            theHeader;
  120.     long                    headerOffset    = 0;
  121.     OSErr                    theErr            = noErr;
  122.     short                    numChannels        = 0,
  123.                             numCommands        = 0,
  124.                             i                = 0;
  125.     Boolean                    parsed            = false;
  126.     unsigned char            headerFormat    = 0;
  127.  
  128.     SndManagerVer = SndSoundManagerVersion ();
  129.  
  130.     /* If SM 3.2 is available, use its ParseSndHeader function */
  131.     if (SndManagerVer.majorRev >= 3 && SndManagerVer.minorAndBugRev >= 32) {
  132.         theErr = ParseSndHeader (theSoundHeader, sndInfo, numFrames, dataOffset);
  133.         parsed = true;
  134.     }
  135.  
  136.     /* If it's not available, or it failed, let's try it ourselves */
  137.     if (theErr != noErr || parsed == false) {
  138.         theErr = noErr;
  139.         switch ((*theSoundHeader)->format) {
  140.             case firstSoundFormat:                    /* Normal 'snd ' resource */
  141.                 if ((*theSoundHeader)->modifierPart->modNumber != kSampledSound) {
  142.                     theErr = badFormat;                /* can only deal with sampled-sound data */
  143.                 }
  144.                 else {
  145.                     numCommands = (*theSoundHeader)->numCommands;
  146.                     if (numCommands != 1) {
  147.                         theErr = badFormat;            /* can only deal with one sound per resource, for now */
  148.                     }
  149.                     else {
  150.                         for (i = 0; i < numCommands; i++) {
  151.                             if ((*theSoundHeader)->commandPart->cmd == kBufferCmd) {
  152.                                 headerOffset = (*theSoundHeader)->commandPart->param2;
  153.                             }
  154.                             else {
  155.                                 theErr = badFormat;    /* can only deal with sampled-sound data */
  156.                             }
  157.                         }
  158.                     }
  159.                 }
  160.                 break;
  161.             case secondSoundFormat:                    /* Hypercard 'snd ' resource */
  162.                 numCommands = ((Snd2ListPtr)(*theSoundHeader))->numCommands;
  163.                 if (numCommands != 1) {
  164.                     theErr = badFormat;                /* can only deal with one sound per resource, for now */
  165.                 }
  166.                 else {
  167.                     for (i = 0; i < numCommands; i++) {
  168.                         if (((Snd2ListPtr)(*theSoundHeader))->commandPart->cmd == kBufferCmd) {
  169.                             headerOffset = ((Snd2ListPtr)(*theSoundHeader))->commandPart->param2;
  170.                         }
  171.                         else {
  172.                             theErr = badFormat;        /* can only deal with sampled-sound data */
  173.                         }
  174.                     }
  175.                 }
  176.                 break;
  177.             default:
  178.                 theErr = badFormat;                    /* unknown resource format */
  179.         }
  180.         if (theErr == noErr) {
  181.             theHeader.standardHeaderPtr = (SoundHeaderPtr)((Ptr)(*theSoundHeader)+headerOffset);
  182.             switch (theHeader.standardHeaderPtr->encode) {
  183.                 case stdSH:
  184.                     theHeader.standardHeaderPtr = (SoundHeaderPtr)((Ptr)(*theSoundHeader)+headerOffset);
  185.                     sndInfo->format            = kOffsetBinary;    /* Can only be raw sounds */
  186.                     switch ((*theSoundHeader)->modifierPart->modInit & kChannelsMask) {
  187.                         case initMono:
  188.                             sndInfo->numChannels    = kMono;
  189.                             break;
  190.                         case initStereo:
  191.                             sndInfo->numChannels    = kStereo;
  192.                             break;
  193.                         default:
  194.                             theErr = badFormat;                    /* unknown number of channels */
  195.                     }
  196.                     sndInfo->sampleSize        = k8BitSample;        /* Can only be 8 bit sounds */
  197.                     sndInfo->sampleRate        = theHeader.standardHeaderPtr->sampleRate;
  198.                     sndInfo->sampleCount    = theHeader.standardHeaderPtr->length;
  199.                     *dataOffset                = headerOffset + sizeof (SoundHeader) - sizeof (short);
  200.                     break;
  201.                 case extSH:
  202.                     theHeader.extendedHeaderPtr = (ExtSoundHeaderPtr)((Ptr)(*theSoundHeader)+headerOffset);
  203.                     sndInfo->format            = kOffsetBinary;    /* Can only be raw sounds */
  204.                     sndInfo->numChannels    = theHeader.extendedHeaderPtr->numChannels;
  205.                     sndInfo->sampleSize        = theHeader.extendedHeaderPtr->sampleSize;
  206.                     sndInfo->sampleRate        = theHeader.extendedHeaderPtr->sampleRate;
  207.                     sndInfo->sampleCount    = theHeader.extendedHeaderPtr->numFrames;
  208.                     *dataOffset                = headerOffset + sizeof (ExtSoundHeader) - sizeof (short);
  209.                     break;
  210.                 case cmpSH:
  211.                     theHeader.compressedHeaderPtr = (CmpSoundHeaderPtr)((Ptr)(*theSoundHeader)+headerOffset);
  212.                     sndInfo->format            = theHeader.compressedHeaderPtr->format;
  213.                     if (sndInfo->format == 0) {
  214.                         switch (theHeader.compressedHeaderPtr->compressionID) {
  215.                             case twoToOne:
  216.                                 sndInfo->format     = kULawSubType;
  217.                                 break;
  218.                             case eightToThree:                    /* I don't know what compressor this is */
  219.                                 theErr = badFormat;
  220.                                 break;
  221.                             case threeToOne:
  222.                                 sndInfo->format     = kMace3SubType;
  223.                                 break;
  224.                             case sixToOne:
  225.                                 sndInfo->format     = kMace6SubType;
  226.                                 break;
  227.                             default:
  228.                                 DebugPrint ("\pUnknown sound format");
  229.                                 theErr = badFormat;
  230.                         }
  231.                     }
  232.                     sndInfo->numChannels    = theHeader.compressedHeaderPtr->numChannels;
  233.                     sndInfo->sampleSize        = theHeader.compressedHeaderPtr->sampleSize;
  234.                     sndInfo->sampleRate        = theHeader.compressedHeaderPtr->sampleRate;
  235.                     sndInfo->sampleCount    = theHeader.compressedHeaderPtr->numFrames;
  236.                     *dataOffset                = headerOffset + sizeof (CmpSoundHeader) - sizeof (short);
  237.                     break;
  238.                 default:
  239.                     theErr = badFormat;        /* A header format we don't know about */
  240.             }
  241.             *numFrames                = (unsigned long)sndInfo->sampleCount;
  242.             sndInfo->flags            = 0;    /* ?? */
  243.             sndInfo->buffer            = 0;    /* should always be 0, data follows header */
  244.             sndInfo->reserved        = 0;    /* just set it to 0 */
  245.         }
  246.  
  247.     }
  248.  
  249.     return theErr;
  250. }
  251.